// $Id: memory.hpp 2 2009-09-02 08:47:42Z joseph2002 $
/*
 * Copyright 2008-2009 Joseph Wu
 * Distributed under the Boost Software License, Version 1.0.
 * (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
 *
 * For more information, see http://xpcomplus.sourceforge.net
 */

#ifndef XPCOM_MEMORY_HPP
#define XPCOM_MEMORY_HPP

#include <xpcom/config.hpp>
#include <cstddef>
#include <xpcom/types.hpp>

#ifdef BOOST_HAS_ABI_HEADERS
#include BOOST_ABI_PREFIX
#endif

namespace xpcom {

//
// The memory namespace provides the standard memory allocation and deallocation
// functionality of XPCOM.  Use functions of this to allocate data when interact
// with XPCOM interfaces and components.
//
// Always use these memory management functions when cross-module memory
// allocation is needed.
//
namespace memory {

XPCOM_DECL void* alloc_data(size_t size);
XPCOM_DECL void* alloc_data_nothrow(size_t size) throw();

// Like realloc in standard library, the original pointer is not freed if
// allocation failed.
XPCOM_DECL void* realloc_data(void* ptr, size_t size);
XPCOM_DECL void* realloc_data_nothrow(void* ptr, size_t size) throw();

XPCOM_DECL void free_data(void* ptr) throw();

XPCOM_DECL void* clone_data(const void* ptr, size_t size);
XPCOM_DECL void* clone_data_nothrow(const void* ptr, size_t size) throw();

//
// Templatized allocation methods for convenience
//
template <typename T>
inline T* alloc(size_t n = 1)
{
    return static_cast<T*>(alloc_data(n * sizeof(T)));
}

template <typename T>
inline T* alloc_nothrow(size_t n = 1) throw()
{
    return static_cast<T*>(alloc_data_nothrow(n * sizeof(T)));
}

template <typename T>
inline T* realloc(T* ptr, size_t n)
{
    return static_cast<T*>(realloc_data(ptr, n * sizeof(T)));
}

template <typename T>
inline T* realloc_nothrow(T* ptr, size_t n) throw()
{
    return static_cast<T*>(realloc_data_nothrow(ptr, n * sizeof(T)));
}

template <typename T>
inline void free(T* ptr) throw()
{
    free_data(ptr);
}

template <typename T>
inline T* clone(const T* ptr, size_t n = 1)
{
    return static_cast<T*>(clone_data(ptr, n * sizeof(T)));
}

template <typename T>
inline T* clone_nothrow(const T* ptr, size_t n = 1) throw()
{
    return static_cast<T*>(clone_data_nothrow(ptr, n * sizeof(T)));
}

template <typename T>
inline void destroy(T* p)
{
    if (p) {
        p->~T();
        free_data(p);
    }
}

} // namespace xpcom::memory

// New tags
struct mem_t {};
struct mem_nothrow_t {};

const mem_t mem = {};
const mem_nothrow_t mem_nothrow = {};

//
// checked_delete using XPCOM memory management.
//
//  Copyright (c) 2002, 2003 Peter Dimov
//  Copyright (c) 2003 Daniel Frey
//  Copyright (c) 2003 Howard Hinnant
//
//  Distributed under the Boost Software License, Version 1.0. (See
//  accompanying file LICENSE_1_0.txt or copy at
//  http://www.boost.org/LICENSE_1_0.txt)
//
//  See http://www.boost.org/libs/utility/checked_delete.html for documentation.
//
// Verify that types are complete for increased safety.
//
template <typename T>
inline void checked_delete(T* x)
{
    // Intentionally complex - simplification causes regressions
    typedef char type_must_be_complete[sizeof(T) ? 1 : -1];
    (void) sizeof(type_must_be_complete);
    //delete x;
    memory::destroy(x);
}

template <typename T>
struct checked_deleter
{
    typedef void result_type;
    typedef T* argument_type;

    void operator()(T* x) const
    {
        // xpcom:: disables ADL
        xpcom::checked_delete(x);
    }
};

} // namespace xpcom

//
// Global overloads of new and delete
//
inline void* operator new(std::size_t size, const xpcom::mem_t&)
{
    return xpcom::memory::alloc_data(size);
}

inline void* operator new[](std::size_t size, const xpcom::mem_t&)
{
    return xpcom::memory::alloc_data(size);
}

inline void* operator new(
        std::size_t size, const xpcom::mem_nothrow_t&) throw()
{
    return xpcom::memory::alloc_data_nothrow(size);
}

inline void* operator new[](
        std::size_t size, const xpcom::mem_nothrow_t&) throw()
{
    return xpcom::memory::alloc_data_nothrow(size);
}

inline void operator delete(void* ptr, const xpcom::mem_t&) throw()
{
    xpcom::memory::free_data(ptr);
}

inline void operator delete[](void* ptr, const xpcom::mem_t&) throw()
{
    xpcom::memory::free_data(ptr);
}

inline void operator delete(void* ptr, const xpcom::mem_nothrow_t&) throw()
{
    xpcom::memory::free_data(ptr);
}

inline void operator delete[](void* ptr, const xpcom::mem_nothrow_t&) throw()
{
    xpcom::memory::free_data(ptr);
}

#ifdef BOOST_HAS_ABI_HEADERS
#include BOOST_ABI_SUFFIX
#endif

#endif // XPCOM_MEMORY_HPP
